<?php

declare(strict_types=1);
namespace App\Controller\active;
use App\Common\Common;
use App\Controller\AbstractController;
use App\Common\User;
use Hyperf\DbConnection\Db;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\RequestMapping;
use App\Common\Message;
/**
 * 兑换码
 */
#[Controller(prefix:"active.RedemptionCode")]
class RedemptionCode extends AbstractController
{

    /**
     * 领取兑换码
     * @return void
     */
    #[RequestMapping(path: "receiveRedemptionCode", methods: "get,post")]
    public function receiveRedemptionCode(){
        $uid = $this->request->post('uid');
        $code = $this->request->post('code');

        $userinfo = Db::table('userinfo')->selectRaw('vip')->where('uid', $uid)->first();
        if (!$userinfo) return $this->ReturnJson->failFul(236); // 用户不存在

        if (!$code) return $this->ReturnJson->successFul(280); // 抱歉!兑换码错误或已关闭

        $code = trim($code);

        // 开始事务
        Db::beginTransaction();
        try {
            // 查询兑换码并锁定 控制一码一用的时候防止多个用户领取同一个兑换码
            $redemption_code = Db::connection('readConfig')
                ->table('redemption_code')
                ->selectRaw('id,cash,bonus,type,vip,starttime,endtime,num')
                ->where(['status' => 1, 'code' => $code])
                ->lockForUpdate() // 锁定行
                ->first();

            if (!$redemption_code) {
                Db::rollBack();
                return $this->ReturnJson->successFul(280); // 抱歉!兑换码错误或已关闭
            }

            // 判断一码多用
            if ($redemption_code['type'] == 2) {
                $resCode = $this->dealWithMoreRedemptionCode($redemption_code, $userinfo);
                if ($resCode != 200) {
                    Db::commit();
                    return $this->ReturnJson->successFul($resCode); // 对应的错误
                }
            }

            // 检查用户是否已经兑换过
            $receiveStatus = $this->getUserUseStatus($uid, $redemption_code['id']);
            if ($receiveStatus) {
                Db::rollBack();
                return $this->ReturnJson->failFul(285); // 抱歉!该兑换码已经兑换了,请勿重复兑换!
            }

            // 检查兑换码数量是否足够
            if ($redemption_code['num'] != -99 && $redemption_code['num'] <= 0) {
                $this->setRedemptionCodeStatus($redemption_code['id'], 2);
                Db::commit();
                return $this->ReturnJson->failFul(281); // 兑换码数量不足
            }

            // 调整兑换码数量
            $this->editRedemptionCodeNum($redemption_code);

            // 插入日志
            $log_data = [
                'uid' => $uid,
                'ip' => Common::getIp(),
                'code' => $code,
                'code_id' => $redemption_code['id'],
                'cash' => $redemption_code['cash'],
                'bonus' => $redemption_code['bonus'],
                'createtime' => time(),
            ];
            Db::table('redemption_code_log')->insert($log_data);

            // 领取奖励
            if ($redemption_code['cash'] > 0) {
                $res = User::userEditCoin($uid, $redemption_code['cash'], 35, '用户:' . $uid . '兑换码兑换' . bcdiv((string)$redemption_code['cash'], '100', 2), 2, 23);
                if (!$res) {
                    Db::rollBack();
                    $this->editRedemptionCodeNum($redemption_code, 1); // 补回次数和状态
                    $this->logger->error('UID:' . $uid . '兑换码兑换失败1!');
                    return $this->ReturnJson->failFul(286); // 兑换失败
                }

                $res = User::editUserTotalGiveScore($uid, $redemption_code['cash']);
                if (!$res) {
                    Db::rollBack();
                    $this->editRedemptionCodeNum($redemption_code, 1); // 补回次数和状态
                    $this->logger->error('UID:' . $uid . '兑换码兑换失败2!');
                    return $this->ReturnJson->failFul(286); // 兑换失败
                }
            }
            if ($redemption_code['bonus'] > 0) {
                $res = User::userEditBonus($uid, $redemption_code['bonus'], 35, '用户:' . $uid . '钱包雨获取' . bcdiv((string)$redemption_code['bonus'], '100', 2), 2, 23);
                if (!$res) {
                    Db::rollBack();
                    $this->editRedemptionCodeNum($redemption_code, 1); // 补回次数和状态
                    $this->logger->error('UID:' . $uid . '兑换码兑换失败3!');
                    return $this->ReturnJson->failFul(286); // 兑换失败
                }
            }

            // 提交事务
            Db::commit();

            // 发送领取成功邮件
            $this->sendMail($uid, bcdiv(bcadd((string)$redemption_code['cash'], (string)$redemption_code['bonus'], 0), '100', 2));

            return $this->ReturnJson->successFul(); // 兑换成功

        } catch (\Exception $e) {
            Db::rollBack();
            $this->logger->error('兑换码处理异常: ' . $e->getMessage());
            return $this->ReturnJson->failFul(502); // 系统繁忙!请稍后再试!
        }
    }



    /**
     * 解析VIP配置
     * @param string $RedemptionCodeVip Vip配置
     * return array
     *
     */
    private function getRedemptionCodeVipConfigArray(string $RedemptionCodeVip):array{
        return explode(',',$RedemptionCodeVip);
    }

    /**
     * 获取用户领取兑换码状态
     * @param $uid  用户UID
     * @param $code_id  兑换码ID
     * @return false|mixed|null
     */
    private function getUserUseStatus($uid,$code_id){
        // 查询用户领取兑换码状态 并控制一个用户同一时间领取一个兑换码
        return Db::table('redemption_code_log')->where(['uid' => $uid,'code_id' => $code_id])->lockForUpdate()->value('id');
    }


    /**
     * 判断一码多用的兑换码是否可以领取
     * @param array $redemption_code 单个兑换码数据
     * @param array $userinfo 用户信息
     * @return int
     */
    private function dealWithMoreRedemptionCode(array $redemption_code,array $userinfo):int{
        //判断数量是否足够
        if($redemption_code['num'] != -99 && $redemption_code['num'] <= 0) {
            $this->setRedemptionCodeStatus($redemption_code['id'],2);
            return 281;
        }
        //检查开始时间
        if($redemption_code['starttime'] && $redemption_code['starttime'] > time() ) return 282;//抱歉!兑换码还没有开始兑换!
        //检查过期时间
        if($redemption_code['endtime'] && $redemption_code['endtime'] < time() ){
            $this->setRedemptionCodeStatus($redemption_code['id'],3);
            return 283;//抱歉!兑换码已经过期!
        }
        //检查VIP等级
        if($redemption_code['vip'] && !in_array($userinfo['vip'],$this->getRedemptionCodeVipConfigArray($redemption_code['vip'])))return 284;//兑换失败，你的账户暂不支持该兑换码
        return 200;
    }

    /**
     *
     * @param array $redemption_code 兑换码
     * @param int $type  类型： 1= 增加兑换码次数,2=减少兑换码次数
     * @return
     */
    private function editRedemptionCodeNum(array $redemption_code,int $type = 2){
        if($redemption_code['num'] == -99)return ;
        if($redemption_code['num'] == 1){
            $type == 2 ?
                $this->setRedemptionCodeStatus($redemption_code['id'],2)
                : $this->setRedemptionCodeStatus($redemption_code['id'],1);
        }else{
            $type == 2 ?
                Db::table('redemption_code')->where('id',$redemption_code['id'])->update(['num' => Db::raw('num - 1')])
                :  Db::table('redemption_code')->where('id',$redemption_code['id'])->update(['num' => Db::raw('num + 1')]);
        }
    }


    /**
     * 判断一码多用的兑换码是否可以领取
     * @param int $code_id 兑换码ID
     * @param int $status 修改兑换码的状态 状态:0=关闭,1=开启,2=已兑完,3=已过期
     * @return
     */
    private function setRedemptionCodeStatus(int $code_id, int $status){
        if($status == 2){
            Db::table('redemption_code')->where('id',$code_id)->update(['status' => $status,'num' => 0]);
        }elseif ($status == 1){
            Db::table('redemption_code')->where('id',$code_id)->update(['status' => $status,'num' => 1]);
        }else{
            Db::table('redemption_code')->where('id',$code_id)->update(['status' => $status]);
        }
    }


    /**
     * 成功发送兑换码邮件
     * @param int|string $uid  用户UID
     * @param string $money  兑换金额
     * @return void
     */
    private function sendMail(int|string $uid,string $money){
        Db::table('user_information')->insert([
            'uid' => $uid,
            'title' => "Redemption Code",
            'content' => "The redemption code has been successfully redeemed,₹$money has been credited to your account, please check it in your wallet. If you have any questions, please contact online customer service",
            'createtime' => time(),
        ]);
    }
}

